package com.airS.task.fileMgr.security.shiro.realm;

import java.io.Serializable;
import java.util.List;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.airS.task.fileMgr.common.constants.FilemgrConstants;
import com.airS.task.fileMgr.common.page.Page;
import com.airS.task.fileMgr.mapper.extra.gk.PermissionExtraMapper;
import com.airS.task.fileMgr.model.gk.Employee;
import com.airS.task.fileMgr.model.gk.Permission;
import com.airS.task.fileMgr.query.gk.EmployeeQuery;
import com.airS.task.fileMgr.security.shiro.session.SessionDAO;
import com.airS.task.fileMgr.security.shiro.token.UsernamePasswordToken;
import com.airS.task.fileMgr.service.gk.EmployeeService;
import com.airS.task.fileMgr.utils.collection.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.util.RequestPairSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 系统安全认证实现类
 * Created by alan on 2017/3/14.
 */
public class SystemAuthorizingRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(SystemAuthorizingRealm.class);

    @Autowired
    private SessionDAO sessionDAO;

    @Autowired
    private EmployeeService employeeService;

    @Autowired
    private PermissionExtraMapper permissionExtraMapper;

    /**
     * authentication认证回调函数
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken authToken = (UsernamePasswordToken) token;

        int activeSessionSize = sessionDAO.getActiveSessions(false).size();
        if (logger.isDebugEnabled()) {
            logger.debug("login submit, active session size: " + activeSessionSize + ", username: "
                    + authToken.getUsername());
        }
        // 身份认证查询
        EmployeeQuery employeeQuery = new EmployeeQuery();
        // 账号校验
        employeeQuery.setAccount(authToken.getUsername());
        Page<Employee> employees = employeeService.queryEmployees(employeeQuery);
        Employee user = CollectionUtils.getFirst(employees.getList());
        if (user == null) {
            throw new AuthenticationException("msg:账号或密码错误, 请重试");
        }
        // 密码校验
        String password = new Sha256Hash(authToken.getPassword(), authToken.getUsername()).toString();
        if (!password.equals(user.getPassword())) {
            throw new AuthenticationException("msg:账号或密码错误, 请重试");
        }
        return new SimpleAuthenticationInfo(new Principal(user), String.valueOf(authToken
                .getPassword()), "SystemRealm");
    }

    /**
     * authorizer授权查询回调函数
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Principal principal = (Principal) getAvailablePrincipal(principals);
        if (principal == null || principal.getEmployeeId() == null) {
            throw new AuthenticationException("msg:账号尚未登录，请登录。");
        }

        List<Permission> permissions = permissionExtraMapper.selectByExample(principal.getEmployeeId());
        if (CollectionUtils.isNotEmpty(permissions)) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            for (Permission permission : permissions) {
                if (StringUtils.isNotBlank(permission.getUrl())) {
                    // 添加基于Permission的权限信息
                    if (permission.getUrl().lastIndexOf("?") != -1) {
                        info.addStringPermission(permission.getUrl().substring(0, permission.getUrl().indexOf("?")));
                    } else {
                        info.addStringPermission(permission.getUrl());
                    }
                }
            }
            // TODO 添加用户角色信息
            // TODO 更新登录IP和时间
            // TODO 记录登录日志
            return info;
        } else {
            return null;
        }
    }

    /**
     * 授权用户信息
     */
    public static class Principal implements Serializable {

        private Integer employeeId;   // 编号
        private String account; // 登录名
        private String employeeName;   // 姓名
        private String organCode;  // 部门编码
        private String organName;  // 部门名称
        private String groupName;  // 分组名称
        private String type;    // 类型
        private String remark;  // 备注

        public Principal(Employee user) {
            this.employeeId = user.getEmployeeId();
            this.account = user.getAccount();
            this.employeeName = user.getEmployeeName();
            this.organCode = user.getOrganCode();
            this.organName = user.getOrganName();
            this.groupName = user.getGroupName();
            this.type = user.getType();
            this.remark = user.getRemark();
        }

        public Integer getEmployeeId() {
            return employeeId;
        }

        public void setEmployeeId(Integer employeeId) {
            this.employeeId = employeeId;
        }

        public String getAccount() {
            return account;
        }

        public void setAccount(String account) {
            this.account = account;
        }

        public String getEmployeeName() {
            return employeeName;
        }

        public void setEmployeeName(String employeeName) {
            this.employeeName = employeeName;
        }

        public String getOrganCode() {
            return organCode;
        }

        public void setOrganCode(String organCode) {
            this.organCode = organCode;
        }

        public String getOrganName() {
            return organName;
        }

        public void setOrganName(String organName) {
            this.organName = organName;
        }

        public String getGroupName() {
            return groupName;
        }

        public void setGroupName(String groupName) {
            this.groupName = groupName;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getRemark() {
            return remark;
        }

        public void setRemark(String remark) {
            this.remark = remark;
        }

        @Override
        public String toString() {
            return String.valueOf(employeeName);
        }

    }

}
